home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
476-500
/
disk_500
/
wiconify
/
wiconsetter.lzh
/
wIconSetter
/
Source
/
ListTree.c
next >
Wrap
C/C++ Source or Header
|
1991-04-19
|
7KB
|
185 lines
/*
* LISTREE.C version 1.0
*
* Converts sorted linked lists to balanced binary trees, and binary trees to
* sorted linked lists. These routines are non-recursive, so we don't have to
* worry about stack size for large lists/trees.
*
* Written for the Commodore Amiga 1000, version 1.3
* using Lattice C v4.0 by Davide P. Cervone
*/
#define NULL 0L
/*
* ListItem is what must be at the head of each item in the list.
* It also doubles as the left and right pointers of the binary tree.
*/
struct ListItem
{
struct ListItem *li_Next;
struct ListItem *li_Prev;
};
#define li_Left li_Next
#define li_Right li_Prev
#define li_BackUp li_Left
#define SKIP_MISSING_NODE (1<<1)
#define NO_MISSING_NODE (1<<0)
/*
* *ListToTree()
*
* Count the items in the list, if they weren't already counted for us.
* Find the smallest power of two greater than the count. If there were
* exactly this many (minus one) items in the list, it would make a perfect
* balanced binary tree. If there are not this many, we will use this basic
* form, but leave some of the lowest level empty. We proceed by assuming
* that it has the full number, and skip items when necessary.
* As we build the tree, all the nodes to the left of the current node will
* be correct, nodes on the right may be modified as we go, however, and
* we will use the li_Right pointer to maintain back pointers to previous
* higher-up nodes in the tree (this takes the place of the recusion stack).
* At any given point, anything interior to the current tree is correctly
* linked, but the nodes along the right-hand (of every level) have their
* li_Right pointers pointing upeward to the level above (towards the root).
* In a perfect binary tree, the binary representation of item's position
* in the list is used to determine its position in the tree: the position
* of the least-significant 1 bit in the number tells which level of the tree
* that item should be in. For example, if the number is 100 (binary), then
* the item is at the third level from the bottom of the tree. The trick will
* be to assign numbers to the items in a list that is not of a perfect length.
*
* The main loop counts off the numbers in the perfect-sized list.
* The next loop finds the node's level within the tree by looking along
* the back pointers (held in li_Right) until we reach the correct level.
* PreviousNode will point to the node to the left of the current item,
* and CurrentNode will become the back pointer for the current item.
* The only nodes that will be missing from a perfect balanced tree will
* be in the bottom level, so if the current item is to be in the bottom
* level (mask == 1) we check for whether we need to skip this position
* in the tree: we could simply check whether num > Count, but this
* would leave all the missing items at one end of the level; we would
* prefer them to be more evenly intermixed, so we reverse the bits in
* num and then do the check.
* If the number is not to be skipped, and there is an item to add,
* We link the previous node into the left of the current node
* and make li_Right point back to the next level up.
* Indicate that no nodes are to be skipped.
* Otherwise indicate that a node (in the perfect tree) is to be skipped.
* The loop is repeated until every node is placed in the tree. The very last
* pass in the loop causes the right-hand nodes to become properly linked,
* and leaves the pointer to the top-most node in the PreviousNode pointer.
* This is returned as the root of the tree.
*/
struct ListItem *ListToTree(CurrentItem,Count)
struct ListItem *CurrentItem;
int Count;
{
struct ListItem *NextItem;
struct ListItem *CurrentNode = NULL;
struct ListItem *NextNode, *PreviousNode;
int num,temp,mask;
int MaxCount;
int MaskStart = NO_MISSING_NODE;
if (Count == 0)
for (NextItem=CurrentItem; NextItem; NextItem=NextItem->li_Next,Count++);
for (MaxCount=1; MaxCount<=Count; MaxCount<<=1);
for (num = 1; num <= MaxCount; num++)
{
PreviousNode = NULL;
for (mask = MaskStart; (num & mask) == 0; mask <<= 1)
{
NextNode = CurrentNode->li_Right;
CurrentNode->li_Right = PreviousNode;
PreviousNode = CurrentNode;
CurrentNode = NextNode;
}
if (mask == 1)
for (temp=MaxCount | num; (temp>>=1)>1; mask = (mask<<1) | (temp & 1));
else
mask = 0;
if (mask <= Count)
{
if (CurrentItem)
{
NextItem = CurrentItem->li_Next;
CurrentItem->li_Left = PreviousNode;
CurrentItem->li_Right = CurrentNode;
CurrentNode = CurrentItem;
CurrentItem = NextItem;
}
MaskStart = NO_MISSING_NODE;
} else {
MaskStart = SKIP_MISSING_NODE;
}
}
return(PreviousNode);
}
/*
* *TreeToList()
*
* Start at the root of the tree, and an empty list
* While there are more items in the tree
* While there are nodes to the left
* Save a pointer to where we last were in the tree
* Move to the left in the tree
* At this point, we have moved as far down the left side of the tree
* as possible, at the same time saving our return path
* Now repeat the following:
* Link the node into the linked list and make it the new list-head
* The next item will be the one to its right, if any
* If there is no item to the right
* Back up to the previous item (and recover the pointer to the node
* before that)
* Repeat this as long as there are no nodes on the right, and as long
* as there is still a current node to work with.
* At this point, we have moved back up the left-hand side of the tree,
* adding nodes to the list until we come to one with a right-hand
* branch. The current node is not the first one on the right, and
* we are ready to go down its left-hand side. This continues until
* all nodes are added to the list. Note that as we proceed, the
* PrevItem pointer may point farther and farther away in the tree.
* Return the completed list.
*/
struct ListItem *TreeToList(theRoot)
struct ListItem *theRoot;
{
struct ListItem *CurItem = theRoot;
struct ListItem *PrevItem = NULL;
struct ListItem *list = NULL;
struct ListItem *NextItem = NULL;
while (CurItem != NULL)
{
while ((NextItem = CurItem->li_Left) != NULL)
{
CurItem->li_BackUp = PrevItem;
PrevItem = CurItem;
CurItem = NextItem;
}
do
{
if (list) list->li_Right = CurItem;
CurItem->li_Left = list;
list = CurItem;
NextItem = CurItem = CurItem->li_Right;
if (CurItem == NULL)
{
CurItem = PrevItem;
if (PrevItem) PrevItem = PrevItem->li_BackUp;
}
} while (NextItem == NULL && CurItem != NULL);
}
return(list);
}